5.3) World
First consider the Table a GameLevel. In that specific enviroment, cards are showed, moved rotated…etc…
We need the world to calculate postions the card place and for the translating: the target position of which the card will head to. Remember that we made a Table texture from a 4x4 Grid.
Now use that and do simple math ;O :
[java]
package magiccard.gameplay
import com.jme3.asset.AssetManager
import com.jme3.material.Material
import com.jme3.math.ColorRGBA
import com.jme3.math.Vector3f
import com.jme3.scene.Node
import com.jme3.scene.Geometry
import com.jme3.scene.Spatial
import com.jme3.scene.shape.Box
import com.jme3.scene.shape.Quad
import sg.atom.gameplay.GameLevel
import sg.atom.stage.GamePlayManager
import sg.atom.stage.WorldManager
import com.jme3.material.RenderState
import com.jme3.renderer.queue.RenderQueue
import com.jme3.scene.shape.Sphere
import com.jme3.math.Quaternion
import com.jme3.math.FastMath
import magiccard.stage.CardSelectControl
import sg.atom.fx.particle.ParticleFactory
import sg.atom.fx.particle.ExplosionNodeControl
import com.jme3.light.PointLight
import com.jme3.effect.ParticleEmitter
class CardTable extends GameLevel{
private Spatial cardOrg;
AssetManager assetManager
// Layout to position cards and table
Vector3f center = new Vector3f(3,0,-5);
float handLength= 2.5f
float spaceBetweenCard = 0.5f
float peakPos= 0.2f
float boardSizeX = 16;
float boardSizeY= 16;
Vector3f scaledCardSize = new Vector3f(1.9f,2.7f,0.02f);
Vector3f gridGapSize = new Vector3f(1,1,1);
public static faceUpQuat = new Quaternion().fromAngles(0f,FastMath.PI,0f);
public static faceDownQuat = new Quaternion().fromAngles(-FastMath.PI,-FastMath.PI,0f);
List actions =[]
public CardTable(GamePlayManager gameplay,WorldManager world,String name,String path){
super(gameplay,world,name,path)
assetManager = world.assetManager
}
Quaternion getCardRot(boolean faceUp){
if (faceUp){
return faceUpQuat.clone()
} else {
return faceDownQuat.clone()
}
}
/*
- Load level, override the method in GameLevel class
*/
public void loadLevel(){
super.loadLevel()
createCardOrg();
createCardBoard();
createEffects();
}
/*
- Short for new Vector3f
*/
Vector3f vec3(float x,float y,float z){
return new Vector3f(x,y,z);
}
/*
- Create the Card board model
*/
public void createCardBoard() {
//levelNode = new Node(“LevelNode”);
Quad cardBoardShape = new Quad(boardSizeX,boardSizeY);
Geometry cardBoard = new Geometry(“CardBoardGeo”, cardBoardShape);
Material mat = new Material(assetManager, “MatDefs/ColoredTextured.j3md”);
mat.setTexture(“ColorMap”, assetManager.loadTexture(“Textures/CardBoard/DiffuseTex.png”));
mat.setColor(“Color”, new ColorRGBA(1, 1, 1, 0.9f));
mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
cardBoard.setMaterial(mat);
cardBoard.setLocalTranslation(center.add((float)(-boardSizeX/2),(float)(-boardSizeY/2),0f));
cardBoard.setQueueBucket(RenderQueue.Bucket.Transparent);
levelNode.attachChild(cardBoard);
}
/*
- For debuging positions
/
public void createSphere(float size,ColorRGBA color,Vector3f pos){
Sphere sh=new Sphere(8,8,size)
Geometry sGeo = new Geometry(“S”,sh)
Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
sGeo.material = mat
mat.setColor(“Color”,color)
sGeo.localTranslation = pos
levelNode.attachChild(sGeo)
}
/
- Create the orginal Card model
*/
public void createCardOrg(){
cardOrg = ((Node) ((Node) assetManager.loadModel(“Models/Cards/Template/card1.j3o”)).getChild(“Card”)).getChild(“Cube1”);
}
public void createDeck(CardPlayer player) {
// create Cards for player
player.currentDeck.cardList.eachWithIndex{card,i->
//fromDeckToHand(player)
def newCard = createCard(card)
}
arrangeDeck(player)
}
public void createHand(CardPlayer player){
player.hand.eachWithIndex{card,i->
//fromDeckToHand(player)
def newCard = createCard(card)
}
arrangeHand(player)
}
public void arrangeDeck(CardPlayer player){
int numOfCards = player.currentDeck.cardList.size()
Vector3f centerDeck = getCenterHandPos(player);
Vector3f gap = vec3(0.4f,0,0.02f);
Vector3f handSize = vec3(0,0,0.5f);
gap = handSize.divide(vec3(1,1,(float) numOfCards));
player.currentDeck.cardList.eachWithIndex{card,i->
//fromDeckToHand(player)
def newCard = card.spatial
//Quaternion rotPIY =new Quaternion().fromAngleAxis(FastMath.PI,Vector3f.UNIT_Y);
//Quaternion rotPIZ =new Quaternion().fromAngleAxis(FastMath.PI,Vector3f.UNIT_Z);
//Quaternion rotXYZ =new Quaternion().fromAngles(0f,FastMath.PI,0f)
//newCard.setLocalRotation(rotXYZ)
Vector3f cardPos = gap.mult(vec3((float)i,1f,(float)i));
Vector3f deckPos;
if (isCurrentPlayer(player)){
deckPos =vec3(9f,-6.5,-5)
} else {
deckPos =vec3(-3f,6.5,-5)
}
newCard.setLocalTranslation(deckPos.add(cardPos))
}
}
public void arrangeHand(CardPlayer player){
int numOfCards = player.hand.size()
Vector3f centerHand = getCenterHandPos(player);
Vector3f gap = vec3(0.4f,0f,0.02f);
float squareSize= boardSizeX-6f
Vector3f handSize = vec3(squareSize,0f,0.02f);
gap = handSize.divide(vec3((float) numOfCards,1,1));
boolean faceUp = isCurrentPlayer(player);
player.hand.eachWithIndex{card,i->
//fromDeckToHand(player)
def newCard = card.spatial
Quaternion rotPIY =new Quaternion().fromAngleAxis(FastMath.PI,Vector3f.UNIT_Y);
Quaternion rotPIZ =new Quaternion().fromAngleAxis(FastMath.PI,Vector3f.UNIT_Z);
Quaternion rotXYZ =getCardRot(faceUp || gamePlayManager.debugMode)
//newCard.setLocalRotation(rotXYZ)
Vector3f cardPos = gap.mult(vec3((float)i,1f,(float)i));
Vector3f handPos = centerHand.add(0f,0f,0f);
//newCard.setLocalTranslation(handPos.add(cardPos));
CardSpatialControl cc=getCardControl(card.spatial)
cc.pos(handPos.add(cardPos))
cc.rot(rotXYZ)
}
}
Geometry createCard(Card card) {
// extract the card info
String path = card.picture
// create the geometry
Geometry newCard = (Geometry) cardOrg.clone();
Material cloneMat = newCard.getMaterial().clone();
cloneMat.setTexture(“ColorMap2”, assetManager.loadTexture(path));
newCard.setMaterial(cloneMat);
//cloneMat.setBoolean(“MixGlow”,true);
levelNode.attachChild(newCard);
card.spatial = newCard;
newCard.setLocalScale(-0.4f,-0.4f,0.4f)
// attach the control
newCard.addControl(new CardSpatialControl(worldManager,card));
newCard.addControl(new CardSelectControl(worldManager,gamePlayManager));
return newCard;
}
CardSpatialControl getCardControl(Spatial spatial){
return spatial.getControl(CardSpatialControl.class)
}
void putToGrave(){
}
boolean isCurrentPlayer(CardPlayer player){
return gamePlayManager.isCurrentPlayer(player)
}
Vector3f getCenterHandPos(CardPlayer player){
Vector3f centerHandPos;
float halfSizeY = (float)((boardSizeY - 0.3f)/2f);
if (isCurrentPlayer(player)){
centerHandPos = center.add(0f,-halfSizeY,0.5f)
} else {
centerHandPos = center.add(0f,halfSizeY,0.5f)
}
return centerHandPos;
}
Vector3f handPos(CardPlayer player,int index,boolean peak){
Vector3f centerHandPos = getCenterHandPos(player)
int numHandCards =player.hand.size()
float indexf=0
if (index == -1){
numHandCards ++
indexf = numHandCards
} else if (index == -2){
indexf = numHandCards + 2
} else if (index == -3){
indexf = numHandCards
numHandCards = 5
}
horizontalPos = handLength * indexf + numHandCards
Vector3f nextCardPos = vec3(0,horizontalPos,0).add(centerHandPos)
if (peak){
nextCardPos.add(vec3(0,peakPos,0))
}
return nextCardPos;
}
Vector3f deckPos(CardPlayer player){
if (isCurrentPlayer(player)){
return vec3(1,1,1)
} else {
return vec3(1,4,1)
}
}
Vector3f gravePos(CardPlayer player){
if (isCurrentPlayer(player)){
return vec3(1,1,1)
} else {
return vec3(1,4,1)
}
}
Vector3f groundPos(CardPlayer player,int index){
if (isCurrentPlayer(player)){
return vec3(-0.8f,-1.7f,-5).add(scaledCardSize.mult(vec3((float)index,0f,0f)))
} else {
return vec3(-0.8f,1.7f,-5).add(scaledCardSize.mult(vec3((float)index,0f,0f)))
}
}
Vector3f magicPos(CardPlayer player,int index){
if (isCurrentPlayer(player)){
return vec3(-0.8f,-4.5f,-5).add(scaledCardSize.mult(vec3((float)index,0f,0f)))
} else {
return vec3(-0.8f,4.5f,-5).add(scaledCardSize.mult(vec3((float)index,0f,0f)))
}
}
void fromDeckToHand(CardPlayer player,Card card){
Vector3f nextCardPos=handPos(player,-3,false)
CardSpatialControl cc=getCardControl(card.spatial)
cc.pos(nextCardPos)
//cc.faceUp()
//cc.moveTo(nextCardPos,3)
}
void fromHandToMagic(CardPlayer player,Card card){
Vector3f nextCardPos=magicPos(player,player.magic.size())
CardSpatialControl cc=getCardControl(card.spatial)
cc.pos(nextCardPos)
cc.rot(getCardRot(false))
}
void fromHandToGround(CardPlayer player,Card card){
Vector3f nextCardPos=groundPos(player,player.ground.size())
CardSpatialControl cc=getCardControl(card.spatial)
cc.pos(nextCardPos)
}
public Vector3f getCamPos(){
return center.add(0f,-8f,20f)
}
void addExplosion(Vector3f pos){
def explosion = explosionPrefab.clone();
explosion.localTranslation =pos.clone();
/*
levelNode.attachChild(flame);
levelNode.attachChild(rain);
levelNode.attachChild(spark);
*/
levelNode.attachChild(explosion);
}
void destroy(CardPlayer player,Card card){
addExplosion(card.spatial.localTranslation)
CardSpatialControl cc=getCardControl(card.spatial)
cc.gigle = true;
actions<<[
time:1f,
do:{
card.spatial.removeFromParent()
}
]
}
public void simpleUpdate(float tpf){
// see if anything queued
for (Iterator it=actions.iterator(); it.hasNext(); ) {
def action = it.next();
if ((action.time -= tpf) <0) {
action.do()
it.remove();
} else {
// do nothing but wait
}
}
}
Node explosionPrefab;
void createEffects(){
ParticleFactory pf = new ParticleFactory(assetManager);
/*
ParticleEmitter flame = pf.createFlame();
flame.setLocalTranslation(new Vector3f(6f,4f,-5f));
ParticleEmitter rain = pf.createRain("");
rain.setLocalTranslation(new Vector3f(0,0,-5f));
ParticleEmitter spark = pf.createSpark();
spark.setLocalTranslation(new Vector3f(0,0,-5f));
*/
explosionPrefab = pf.createExplosionNode();
explosionPrefab.getControl(ExplosionNodeControl.class).setMaxTime(2f)
}
public void loadCharacters(){
Quaternion rot= new Quaternion().fromAngleAxis(FastMath.HALF_PI,Vector3f.UNIT_X)
/*
Spatial demon = assetManager.loadModel(“Models/Demons/BlueEyeWhiteDragon/BlueEyes.j3o”);
demon.scale(0.04f);
demon.setLocalRotation(rot);
levelNode.attachChild(demon);
*/
Spatial witch = assetManager.loadModel(“Models/Demons/Magicians/White/WhiteFemaleMagician.j3o”);
witch.scale(0.5f);
witch.setLocalTranslation(new Vector3f(3f,4f,-5f));
witch.setLocalRotation(rot);
levelNode.attachChild(witch);
Spatial samurai = assetManager.loadModel(“Models/Demons/Warior/SamuraiWarior.j3o”);
samurai.setLocalTranslation(new Vector3f(6f,4f,-5f));
samurai.scale(0.5f);
samurai.setLocalRotation(rot);
levelNode.attachChild(samurai);
/** A white, spot light source. */
PointLight lamp = new PointLight();
lamp.setPosition(getCamPos());
lamp.setColor(ColorRGBA.White);
levelNode.addLight(lamp);
}
}
[/java]
Explanation:
The CardTable take care of 3 things:
(1| Creating:
- - Its self from a 16x16 Quad and the Texture
- - The Cards from the OrgCard model with appropriate picture
- - The effects
- - The 3D models
(2| Destroying things in delayed fashion:
- - Explode the Card (cool effect!)
(3| Calculate the postions,directions of all action triggered by GamePlay. Arrange and reArrange the cards in hands, in Deck.
handPos,gravePos,groundPos, deckPos...etc
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
5.4) Select:
This section is quite advance for who don't similar with groovy but keep your self cheerful cause you going to enjoy Groovy as much as I do!
In Atom, I introduce a generic way to hook your select function into your code game mechanic.
Short:
Detailed:
For this card game, we will implement a few things in this designed mechanic:
5.4.a) Select function:
[java]
// Add later
[/java]
5.4.b) Select condition:
[java]
// Add later
[/java]
5.4.c) Select control:
CardSelectControl.java
[java]
package magiccard.stage;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import sg.atom.stage.WorldManager;
import sg.atom.stage.select.SpatialSelectControl;
import magiccard.gameplay.CardGamePlay;
import magiccard.gameplay.Card;
import magiccard.gameplay.CardSpatialControl;
import sg.atom.stage.select.EntitySelectCondition;
/**
*
-
@author cuong.nguyenmanh2
*/
public class CardSelectControl extends SpatialSelectControl {
private Vector3f bigScale;
private Vector3f orginalScale;
private Vector3f orginalPos;
private Vector3f peakPos;
private boolean skipOutHover;
private String currentFunction;
private CardGamePlay gameplay;
private Card card;
private boolean isBigger = false;
private boolean isPeak = false;
private boolean isHighlight = false;
public CardSelectControl(WorldManager worldManager, CardGamePlay gameplay) {
currentFunction = “Normal”;
this.gameplay = gameplay;
}
@Override
public void setSpatial(Spatial spatial) {
super.setSpatial(spatial);
this.card = (Card) spatial.getControl(CardSpatialControl.class).getEntity();
orginalScale = spatial.getLocalScale().clone();
bigScale = orginalScale.mult(1.2f);
orginalPos = spatial.getLocalTranslation().clone();
}
@Override
protected void doSelected() {
super.doSelected();
//orginalScale = spatial.getLocalScale();
//orginalPos = spatial.getLocalTranslation().clone();
//peakPos = orginalPos.add(new Vector3f(0f, 0.4f, 0f));
//spatial.setLocalTranslation(peakPos);
//spatial.setLocalScale(bigScale);
}
@Override
protected void doDeselected() {
super.doDeselected();
//spatial.setLocalScale(orginalScale);
//spatial.setLocalTranslation(orginalPos.clone());
}
@Override
protected void doHovered() {
if (this.isHoverable()) {
super.doHovered();
//orginalScale = spatial.getLocalScale();
EntitySelectCondition inHand = (EntitySelectCondition) gameplay.cardSelectRules.get(“inHand”);
EntitySelectCondition inGround = (EntitySelectCondition) gameplay.cardSelectRules.get(“inGround”);
if (inHand.isSelected(card)) {
peak();
bigger();
highlight();
} else if (inGround.isSelected(card)) {
// The card is the ground
highlight();
}
}
}
@Override
protected void doOutHovered() {
if (this.isHoverable()) {
if (!this.skipOutHover) {
super.doOutHovered();
noPeak();
smaller();
noHighlight();
}
}
}
public String getCurrentFunction() {
return currentFunction;
}
public void setCurrentFunction(String currentFunction) {
this.currentFunction = currentFunction;
}
public void setSkipOutHover(boolean skipOutHover) {
this.skipOutHover = skipOutHover;
}
public boolean isSkipOutHover() {
return skipOutHover;
}
void bigger() {
if (!isBigger) {
spatial.setLocalScale(bigScale);
isBigger = true;
}
}
void peak() {
if (!isPeak) {
orginalPos = spatial.getLocalTranslation().clone();
peakPos = orginalPos.add(new Vector3f(0f, 0.2f, 0.2f));
spatial.setLocalTranslation(peakPos);
isPeak = true;
}
}
void noPeak() {
if (isPeak) {
spatial.setLocalTranslation(orginalPos.clone());
isPeak = false;
}
}
void smaller() {
if (isBigger) {
spatial.setLocalScale(orginalScale);
isBigger = false;
}
}
void highlight() {
if (!isHighlight) {
((Geometry) spatial).getMaterial().setBoolean(“MixGlow”, true);
isHighlight = true;
}
}
void noHighlight() {
if (isHighlight) {
((Geometry) spatial).getMaterial().setBoolean(“MixGlow”, false);
isHighlight = false;
}
}
}
[/java]
5.4.d) Cached conditions - Rules:
We use a Groovy Map cardSelectRules to save all rule in form of Closure that determine if a Card is selected or not.
…part of CardGamePlay.groovy
[java]
public Map cardSelectRules=[:];
void createSelectConditions(){
// RULE : The card is in hand
def inHandRule ={card->
CardPlayer player = whichPlayerCard(card)
if (player.getHand().contains(card)) {
return true;
}
return false;
}
cardSelectRules[“inHand”] =new ClosureSelectCondition(inHandRule);
// RULE : The card is in hand of the current player - who play this device!
def inHandCurrentRule ={card->
if (isCurrentPlayer(whichPlayerCard(card))) {
CardPlayer player = getCurrentPlayer();
if (player.getHand().contains(card)) {
return true;
}
}
return false;
}
cardSelectRules[“inHandCurrent”] =new ClosureSelectCondition(inHandCurrentRule);
// RULE : The card is in hand of the current turn player - who has this turn!
def inHandTurnRule ={card->
if (isCurrentPlayer(whichPlayerCard(card))) {
CardPlayer player = getCurrentPlayer();
if (player.getHand().contains(card)) {
return true;
}
}
return false;
}
cardSelectRules[“inHandTurn”] =new ClosureSelectCondition(inHandTurnRule);
// RULE: The card is in ground
def inGroundRule ={card->
CardPlayer player = whichPlayerCard(card);
if (player.ground.contains(card)) {
return true;
}
return false;
}
cardSelectRules[“inGround”] =new ClosureSelectCondition(inGroundRule);
// RULE: Card in player Main phase
def mainPhaseCards = {card->
if (isCurrentPlayer(whichPlayerCard(card))) {
CardPlayer player = getCurrentPlayer();
if (player.hand.contains(card)||player.ground.contains(card)||player.magic.contains(card)) {
//println(“Condition true”);
return true;
}
}
return false;
}
cardSelectRules[“mainPhaseCards”] =new ClosureSelectCondition(mainPhaseCards);
// RULE: Can not select any thing
def noneSelect = {card->
return false;
}
cardSelectRules[“noneSelect”] =new ClosureSelectCondition(noneSelect);
}
[/java]
[=============================== TO BE CONTINUE=====================================================]
Scroll to next few posts to continue, I have trouble with long posts in WordPress!! 