Skip to content

Commit fb68702

Browse files
author
Julien Poulton
committed
Merge branch 'tooltip-module' into 'master'
[Feat][SDK] Tooltip module See merge request codingame/game-engine!171
2 parents 9a539d1 + 96e3ae3 commit fb68702

File tree

6 files changed

+340
-4
lines changed

6 files changed

+340
-4
lines changed

engine/modules/endscreen/src/main/resources/view/endscreen-module/EndScreenModule.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {WIDTH, HEIGHT} from '../core/constants.js'
22
import {lerp, unlerp} from '../core/utils.js'
33
import {ErrorLog} from '../core/ErrorLog.js'
44
import {MissingImageError} from './errors/MissingImageError.js'
5-
import {flagForDestructionOnReinit} from '../core/rendering.js'
5+
66
/* global PIXI */
77

88
export class EndScreenModule {

engine/modules/tooltip/pom.xml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<groupId>com.codingame</groupId>
7+
<artifactId>gameengine</artifactId>
8+
<version>master-SNAPSHOT</version>
9+
<relativePath>../../../pom.xml</relativePath>
10+
</parent>
11+
12+
<groupId>com.codingame.gameengine</groupId>
13+
<artifactId>module-tooltip</artifactId>
14+
<name>CodinGame Game Engine Tooltip Module</name>
15+
<description>A module to display tooltips for the CodinGame engine toolkit.</description>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>com.codingame.gameengine</groupId>
20+
<artifactId>core</artifactId>
21+
<version>${project.version}</version>
22+
</dependency>
23+
<dependency>
24+
<groupId>com.codingame.gameengine</groupId>
25+
<artifactId>module-entities</artifactId>
26+
<version>${project.version}</version>
27+
</dependency>
28+
</dependencies>
29+
30+
</project>
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.codingame.gameengine.module.tooltip;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
import com.codingame.gameengine.core.AbstractPlayer;
7+
import com.codingame.gameengine.core.GameManager;
8+
import com.codingame.gameengine.core.Module;
9+
import com.codingame.gameengine.module.entities.Entity;
10+
import com.codingame.gameengine.module.entities.GraphicEntityModule;
11+
import com.google.inject.Inject;
12+
import com.google.inject.Singleton;
13+
14+
/**
15+
* The TooltipModule takes care of displaying tooltips under the mouse cursor when an element has a linked tooltip text.
16+
*
17+
*/
18+
@Singleton
19+
public class TooltipModule implements Module {
20+
21+
GameManager<AbstractPlayer> gameManager;
22+
@Inject GraphicEntityModule entityModule;
23+
Map<Integer, String> registered, newRegistration;
24+
25+
@Inject
26+
TooltipModule(GameManager<AbstractPlayer> gameManager) {
27+
this.gameManager = gameManager;
28+
gameManager.registerModule(this);
29+
registered = new HashMap<>();
30+
newRegistration = new HashMap<>();
31+
}
32+
33+
@Override
34+
public void onGameInit() {
35+
sendFrameData();
36+
}
37+
38+
@Override
39+
public void onAfterGameTurn() {
40+
sendFrameData();
41+
}
42+
43+
@Override
44+
public void onAfterOnEnd() {}
45+
46+
private void sendFrameData() {
47+
Object[] data = { newRegistration };
48+
gameManager.setViewData("tooltips", data);
49+
50+
newRegistration.clear();
51+
}
52+
53+
private boolean stringEquals(String a, String b) {
54+
if (a == b) {
55+
return true;
56+
} else if (a != null && a.equals(b)) {
57+
return true;
58+
} else {
59+
return false;
60+
}
61+
}
62+
63+
/**
64+
* Sets a tooltip text linked to an entity
65+
*
66+
* @param entity
67+
* @param text is the tooltip text that will be displayed when hovering over the entity
68+
*/
69+
public void setTooltipText(Entity<?> entity, String text) {
70+
int id = entity.getId();
71+
if (!stringEquals(text, registered.get(id))) {
72+
newRegistration.put(id, text);
73+
registered.put(id, text);
74+
}
75+
}
76+
77+
/**
78+
*
79+
* @param entity
80+
* @return the tooltip text liked to the entity
81+
*/
82+
public String getTooltipText(Entity<?> entity) {
83+
return registered.get(entity.getId());
84+
}
85+
86+
/**
87+
* Removes the tooltip text linked to the entity
88+
* @param entity
89+
*/
90+
public void removeTooltipText(Entity<?> entity) {
91+
newRegistration.put(entity.getId(), null);
92+
registered.remove(entity.getId());
93+
}
94+
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import { WIDTH, HEIGHT } from '../core/constants.js'
2+
import { api as entityModule } from '../entity-module/GraphicEntityModule.js'
3+
4+
/* global PIXI */
5+
6+
function getMouseOverFunc (id, tooltip) {
7+
return function () {
8+
tooltip.inside[id] = true
9+
}
10+
}
11+
12+
function getMouseOutFunc (id, tooltip) {
13+
return function () {
14+
delete tooltip.inside[id]
15+
}
16+
}
17+
18+
function getEntityState (entity, frame) {
19+
const subStates = entity.states[frame]
20+
if (subStates && subStates.length) {
21+
return subStates[subStates.length - 1]
22+
}
23+
return null
24+
}
25+
26+
function getMouseMoveFunc (tooltip, container, module) {
27+
return function (ev) {
28+
if (tooltip) {
29+
var pos = ev.data.getLocalPosition(container)
30+
tooltip.x = pos.x
31+
tooltip.y = pos.y
32+
33+
const showing = []
34+
const ids = Object.keys(tooltip.inside).map(n => +n)
35+
36+
for (let id of ids) {
37+
if (tooltip.inside[id]) {
38+
const entity = entityModule.entities.get(id)
39+
const state = entity && getEntityState(entity, module.currentFrame.number)
40+
if (!state) {
41+
delete tooltip.inside[id]
42+
} else {
43+
showing.push(id)
44+
}
45+
}
46+
}
47+
48+
if (showing.length) {
49+
const tooltipBlocks = []
50+
for (let show of showing) {
51+
const entity = entityModule.entities.get(show)
52+
const state = getEntityState(entity, module.currentFrame.number)
53+
if (state !== null) {
54+
tooltip.visible = true
55+
const text = module.currentFrame.registered[show]
56+
if (text && text.length && String(text).valueOf() !== '0') {
57+
tooltipBlocks.push(text)
58+
}
59+
}
60+
}
61+
tooltip.label.text = tooltipBlocks.join('\n──────────\n')
62+
} else {
63+
tooltip.visible = false
64+
}
65+
66+
tooltip.background.width = tooltip.label.width + 20
67+
tooltip.background.height = tooltip.label.height + 20
68+
69+
tooltip.pivot.x = -30
70+
tooltip.pivot.y = -50
71+
72+
if (tooltip.y - tooltip.pivot.y + tooltip.height > HEIGHT) {
73+
tooltip.pivot.y = 10 + tooltip.height
74+
tooltip.y -= tooltip.y - tooltip.pivot.y + tooltip.height - HEIGHT
75+
}
76+
77+
if (tooltip.x - tooltip.pivot.x + tooltip.width > WIDTH) {
78+
tooltip.pivot.x = tooltip.width
79+
}
80+
}
81+
}
82+
};
83+
84+
export class TooltipModule {
85+
constructor (assets) {
86+
this.interactive = {}
87+
this.previousFrame = {
88+
registered: {}
89+
}
90+
this.lastProgress = 1
91+
this.lastFrame = 0
92+
}
93+
94+
static get name () {
95+
return 'tooltips'
96+
}
97+
98+
updateScene (previousData, currentData, progress) {
99+
this.currentFrame = currentData
100+
this.currentProgress = progress
101+
}
102+
103+
handleFrameData (frameInfo, data) {
104+
if (!data) {
105+
return
106+
}
107+
const newRegistration = data[0]
108+
const registered = { ...this.previousFrame.registered, ...newRegistration }
109+
110+
Object.keys(newRegistration).forEach(
111+
k => {
112+
this.interactive[k] = true
113+
}
114+
)
115+
116+
const frame = { registered, number: frameInfo.number }
117+
this.previousFrame = frame
118+
return frame
119+
}
120+
121+
reinitScene (container) {
122+
this.tooltip = this.initTooltip()
123+
entityModule.entities.forEach(entity => {
124+
if (this.interactive[entity.id]) {
125+
entity.container.interactive = true
126+
entity.container.mouseover = getMouseOverFunc(entity.id, this.tooltip)
127+
entity.container.mouseout = getMouseOutFunc(entity.id, this.tooltip)
128+
}
129+
})
130+
this.container = container
131+
container.interactive = true
132+
container.mousemove = getMouseMoveFunc(this.tooltip, container, this)
133+
container.addChild(this.tooltip)
134+
}
135+
136+
generateText (text, size, color, align) {
137+
var textEl = new PIXI.Text(text, {
138+
fontSize: Math.round(size / 1.2) + 'px',
139+
fontFamily: 'Lato',
140+
fontWeight: 'bold',
141+
fill: color
142+
})
143+
144+
textEl.lineHeight = Math.round(size / 1.2)
145+
if (align === 'right') {
146+
textEl.anchor.x = 1
147+
} else if (align === 'center') {
148+
textEl.anchor.x = 0.5
149+
}
150+
151+
return textEl
152+
};
153+
154+
initTooltip () {
155+
var tooltip = new PIXI.Container()
156+
var background = tooltip.background = new PIXI.Graphics()
157+
var label = tooltip.label = this.generateText('', 36, 0xFFFFFF, 'left')
158+
159+
background.beginFill(0x0, 0.7)
160+
background.drawRect(0, 0, 200, 185)
161+
background.endFill()
162+
background.x = -10
163+
background.y = -10
164+
165+
tooltip.visible = false
166+
tooltip.inside = {}
167+
168+
tooltip.addChild(background)
169+
tooltip.addChild(label)
170+
171+
tooltip.interactiveChildren = false
172+
return tooltip
173+
};
174+
}

playground/extensions/extensions-3-tooltip.md

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,44 @@ This module can be used to assign some data to an entity from the [GraphicEntity
44

55
You may change the assigned data of each entity once per game turn.
66

7-
The majority of the text to display should be written into your copy of the tooltip module to reduce the amount of data the Referee must produce.
7+
## Import
8+
⚠ This module requires the [GraphicEntityModule](https://github.com/CodinGame/codingame-game-engine/tree/master/engine/modules/entities) to work.
89

9-
⚠ This example might require you modify it for proper use in your own game.
10+
Add the dependency in the `pom.xml` of your project.
11+
```xml
12+
<dependency>
13+
<groupId>com.codingame.gameengine</groupId>
14+
<artifactId>module-tooltip</artifactId>
15+
<version>3.2.0</version>
16+
</dependency>
17+
```
18+
And load the module in your `config.js`.
19+
```javascript
20+
import { GraphicEntityModule } from './entity-module/GraphicEntityModule.js';
21+
import { TooltipModule } from './tooltip-module/TooltipModule.js';
22+
23+
export const modules = [
24+
GraphicEntityModule,
25+
TooltipModule
26+
];
27+
```
28+
29+
## Usage
30+
31+
`Referee.java`
32+
```java
33+
@Inject TooltipModule tooltips;
34+
35+
@Override
36+
public void init() {
37+
// adding a tooltip to an entity
38+
tooltips.setTooltipText(myEntity, "the tooltip text linked to this entity");
39+
40+
// removing the tooltip from an other entity
41+
tooltips.removeTooltipText(otherEntity);
42+
43+
// getting the tooltip text associated to an entity
44+
String text = tooltips.getTooltipText(myEntity);
45+
// in this case text will now be "the tooltip text linked to this entity"
46+
}
47+
```

playground/misc/misc-3-release-notes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The CodinGame SDK is regularly updated and improved. This document lets you know
66

77
### 🎁 New feature
88

9-
- The [EndScreenModule](playground/extensions/extensions-4-endscreen.md) is now bundled with the sdk.
9+
- The [EndScreenModule](playground/extensions/extensions-4-endscreen.md) and the [TooltipModule](playground/extensions/extensions-3-tooltip.md) are now bundled with the sdk.
1010
- The [ToggleModule](playground/extensions/extensions-toggle.md) has been added.
1111

1212
### 🐞 Bug fix

0 commit comments

Comments
 (0)